package sisicotren.model.simulator;

import estadistica.PoissonEventGenerator;
import sisicotren.model.simulator.System;
import sisicotren.util.Log;
import java.util.Observable;

enum ClientsInjectorState {
	CREATED,
	RUNNING,
	PAUSED,
	FINISHED
}

public class ClientsInjector extends Observable implements Runnable {
	
	// cantidad de clientes por minuto.
	public ClientsInjector(Double tasaArribos, System system) {
		state = ClientsInjectorState.CREATED;
		evtGenerator = new PoissonEventGenerator(tasaArribos);
		clientsInjected = 0;
		theSystem = system;
	}
	
	public void run() {
		Double lastEvtGen = 0.00;
		state = ClientsInjectorState.RUNNING;
		while(state != ClientsInjectorState.FINISHED) {
			if(state == ClientsInjectorState.RUNNING) {
				Double nextEvtTime = evtGenerator.getNextEventTime();
				Double delta = nextEvtTime - lastEvtGen;
				try {
					Log.print("ClientsInjector, Sleep :[" + (long)(delta * ClientsInjector.time.time() * 1000.00) +"]");
					Thread.sleep((long)(delta * ClientsInjector.time.time() * 1000.00));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// podria haberse desactivado el injector durante el sleep
				if(state == ClientsInjectorState.RUNNING) {
					theSystem.inject(new Client(nextEvtTime));
					clientsInjected++;
					Log.print("ClientsInjector, Inject another client. Total :[" + clientsInjected +"]");
					lastEvtGen = nextEvtTime;
					this.setChanged();
					this.notifyObservers(clientsInjected);
				}
			}
			Thread.yield();
			
		}
		Log.print("ClientsInjector, end of inject.");
	}
	
	public void stop() {
		state = ClientsInjectorState.FINISHED;
	}
	
	public void resume() {
		state = ClientsInjectorState.RUNNING;
	}
	
	public void pause() {
		state = ClientsInjectorState.PAUSED;
	}
	
	public Integer getClientsInjected() {
		return clientsInjected;
	}
	
	public static SimulationTimeOptions getTimeOptions() {
		return ClientsInjector.time;
	}
	
	public static void setTimeOptions(SimulationTimeOptions time) {
		ClientsInjector.time = time;
	}
	
	private PoissonEventGenerator evtGenerator;
	private int clientsInjected;
	private System theSystem;
	private ClientsInjectorState state;
	private static SimulationTimeOptions time = SimulationTimeOptions.REAL_TIME;
}
